package com.oneguy.control;

import com.alibaba.fastjson.JSON;
import com.oneguy.Constants;
import com.oneguy.Log;
import com.oneguy.model.AccessToken;
import com.oneguy.model.WeixinTextMessage;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.util.EntityUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;

/**
 * Created by ZuoShu on 16/12/28.
 */
public class MessageHelper {
    private static final String TAG = "MessageHelper";
    private static final String URL =
            "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
                    + Constants.APP_ID + "&secret=" + Constants.APP_SECRET;
    private static final String SEND_MESSAGE_URL =
            "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=";
    private static final long EXPRIED_TIME = 20 * 60 * 1000;
    private static final int MAX_TRY = 5;


    private AccessToken accessToken;

    private static MessageHelper instance;

    public synchronized static MessageHelper getInstance() {
        if (instance == null) {
            instance = new MessageHelper();
        }
        return instance;
    }

    public void sendMessage(String username, String content) {
        long now = System.currentTimeMillis();
        int tryTimes = 0;
        while ((accessToken == null || now - accessToken.getGainTime() >= EXPRIED_TIME)
                && tryTimes <= 5) {
            updateToken();
            tryTimes++;
        }
        WeixinTextMessage message = new WeixinTextMessage();
        message.setMsgType("text");
        message.setToUser(username);
        message.setText(new WeixinTextMessage.Text(content));

        final CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
        httpclient.start();

        final HttpPost request = new HttpPost(SEND_MESSAGE_URL + accessToken.getAccessToken());
        Log.i(TAG, "content:" + JSON.toJSONString(message));
        StringEntity entity = new StringEntity(JSON.toJSONString(message), "utf-8");
        entity.setContentEncoding("UTF-8");
        entity.setContentType("application/json");
        request.setEntity(entity);
        httpclient.execute(request, new FutureCallback<HttpResponse>() {

            public void completed(final HttpResponse response) {
                try {
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                    Log.i(TAG, "send message completed:" + content);
                    IOUtils.closeQuietly(httpclient);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            public void failed(final Exception ex) {
                Log.e(TAG, "send message failed", ex);
                IOUtils.closeQuietly(httpclient);
            }

            public void cancelled() {
                Log.i(TAG, "send message cancelled");
                IOUtils.closeQuietly(httpclient);
            }

        });
    }

    private void updateToken() {
        CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
        httpclient.start();

        final CountDownLatch latch = new CountDownLatch(1);
        final HttpGet request = new HttpGet(URL);

        httpclient.execute(request, new FutureCallback<HttpResponse>() {

            public void completed(final HttpResponse response) {
                latch.countDown();
                try {
                    String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                    accessToken = JSON.parseObject(content, AccessToken.class);
                    accessToken.setGainTime(System.currentTimeMillis());
                    Log.i(TAG, "update access token:" + accessToken.getAccessToken());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            public void failed(final Exception ex) {
                latch.countDown();
            }

            public void cancelled() {
                latch.countDown();
            }
        });
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            httpclient.close();
        } catch (IOException ignore) {
        }
    }


}
